#include "rsa.h"
#include <QDebug>
#include <QTime>
#include <qcoreapplication.h>
#include <QCoreApplication>
#include <QDateTime>
#include <iostream>
rsa::rsa()
{
    e=0;
}
int rsa::RSA_Delay(){
    QTime dieTime = QTime::currentTime().addMSecs(2115);
    while( QTime::currentTime() < dieTime )
       QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
    return 0;
}

int rsa::BianaryTransform(int num, int bin_num[])
{

    int i = 0,  mod = 0;
    //转换为二进制，逆向暂存temp[]数组中
    while(num != 0)
    {
        mod = num%2;
        bin_num[i] = mod;
        num = num/2;
        i++;
    }
    //返回二进制数的位数
    return i;
}
//模重复平方算法
long long rsa::Modular_Exonentiation(long long a, int b, int n)
{
    int c = 0, bin_num[1000];
    long long d = 1;
    int k = BianaryTransform(b, bin_num)-1;

    for(int i = k; i >= 0; i--)
    {
        c = 2*c;
        d = (d*d)%n;
        if(bin_num[i] == 1)
        {
            c = c + 1;
            d = (d*a)%n;
        }
    }
    return d;
}
int rsa::Exgcd(int m,int n,int &x)
{
    int x1,y1,x0,y0, y;
    x0=1; y0=0;
    x1=0; y1=1;
    x=0; y=1;
    int r=m%n;
    int q=(m-r)/n;
    while(r)
    {
        x=x0-q*x1; y=y0-q*y1;
        x0=x1; y0=y1;
        x1=x; y1=y;
        m=n; n=r; r=m%n;
        q=(m-r)/n;
    }
    return n;
}
// 生成伪素数

size_t rsa::Pseudoprime()
{
    int MAX_ROW = 50;
    bool ifprime = false;
    size_t a = 0;
    int arr[MAX_ROW];   //数组arr为{3，4，5，6...52}
    for (int i = 0; i<MAX_ROW; ++i)
    {
        arr[i] = i+3;
    }
    while (!ifprime)
    {
        srand((unsigned)time(0));
        ifprime = true;
        a = ((rand()+30)%1000)*2+3; //生成一个范围在3到2003里的奇数
        for (int j = 0; j<MAX_ROW; ++j)
        {
            if (a%arr[j] == 0)//如果a可以被arr中的一个数整除，则a不是素数
            {
                ifprime = false;
                break;
            }
        }
    }
    return a;
}
//Miller-Rabin素数检测
bool rsa::rabinmiller(size_t n, size_t k)
{

    int s = 0;
    int temp = n-1;
    while ((temp & 0x1) == 0 && temp)
    {
        temp = temp>>1;
        s++;
    }   //将n-1表示为(2^s)*t
    size_t t = temp;

    while(k--)  //判断k轮误判概率不大于(1/4)^k
    {
        srand((unsigned)time(0));
        size_t b = rand()%(n-2)+2; //生成一个b(2≤a ≤n-2)

        size_t y = Modular_Exonentiation(b,t,n);
        if (y == 1 || y == (n-1))
            return true;
        for(int j = 1; j<=(s-1) && y != (n-1); ++j)
        {
            y = Modular_Exonentiation(y,2,n);
            if (y == 1)
                return false;
        }
        if ( y != (n-1))
            return false;
    }
    return true;
}
void rsa::RSA_Initialize()//RSA初始化
{
flag1:    int i;
    for(i=0;i<MAX_LENTH;i++){
        Plaintext[i]=0;
        Ciphertext[i]=0;
        plaintext[i]=0;
        ciphertext[i]=0;
    }
    size_t p,q;
   //生成两个素数p,q
   while(true){
   p = Pseudoprime();
   if(rabinmiller(p,10)){
       break;
   }
   }
   qDebug()<<"p="<<p;
   while(true){
   RSA_Delay();
   q = Pseudoprime();
   if(rabinmiller(q,10)){
       break;
   }
   }
   qDebug()<<"q="<<q;
   n = p*q;
   fain= (p-1)*(q-1);
   qDebug()<<"n="<<n;
   qDebug()<<"fain="<<fain;
   //用欧几里德扩展算法求e,d
   for(int j = 3; j < fain; j+=1331)
   {
       int gcd = Exgcd(j, fain, d);
       if( gcd == 1 && d > 0)
       {
           e = j;
           break;
       }
   }
   if(e==0)goto flag1;
   qDebug()<<"e="<<e;
   qDebug()<<"d="<<d;
   return;
}
void rsa::Initialize()
{

    int i;
    int len;
    len=strlen((char*)plaintext);
    if(len>MAX_LENTH){
        qDebug()<<"too long to RSA";
        return;
    }
    for(i=0;i<len;i++){
        Plaintext[i]=(int)plaintext[i];
        Ciphertext[i]=(int)ciphertext[i];
    }
    for(i=0;i<len;i++){
        std::cout<<Plaintext[i]<<" ";
        if((i+1)%4==0)
            std::cout<<"\n";
    }
    std::cout<<"\n============"<<"\n";
}
void rsa::RSA_Encrypt()//加密
{
    int len=strlen((char*)plaintext);//明文字符数组长度
    int i = 0;
    for(i = 0; i < len; i++){
        Ciphertext[i] = Modular_Exonentiation(Plaintext[i], e, n);//公钥加密
        ciphertext[i]=(char)(32+Ciphertext[i]%94);
    }
    std::cout<<"======Ciphertext=======\n";
    for(i=0;i<len;i++){
        std::cout<<Ciphertext[i]<<" ";
        if((i+1)%4==0)
            std::cout<<"\n";
    }
    std::cout<<"\n======ciphertext======\n";
    for(i=0;i<len;i++){
        std::cout<<ciphertext[i]<<" ";
        if((i+1)%4==0)
            std::cout<<"\n";
    }
}
void rsa::RSA_Decrypt()//解密
{

    int len=16;//密文字符数组长度
    int i = 0;
    qDebug()<<"========Ciphertext====\n";
    for(i=0;i<len;i++){
        std::cout<<Ciphertext[i]<<" ";
        if((i+1)%4==0)
            std::cout<<"\n";
    }
    std::cout<<"\n";
    qDebug()<<"=============";
    for(i = 0; i < len; i++){
        Plaintext[i] = Modular_Exonentiation(Ciphertext[i], d, n);//私钥解密
        plaintext[i]=(char)Plaintext[i];
    }
    qDebug()<<"======明文======\n";
    for(i=0;i<len;i++){
        std::cout<<plaintext[i]<<" ";
        if(i%4==0&&i!=0)std::cout<<"\n";
    }
}
void rsa::RSA_Signature()//签名
{
    int len=strlen((char*)plaintext);//明文字符数组长度
    int i = 0;
    for(i = 0; i < len; i++){
        Ciphertext[i] = Modular_Exonentiation(Plaintext[i], d, n);//私钥签名
        ciphertext[i]=(char)(32+Ciphertext[i]%94);
    }
    std::cout<<"======Signature=======\n";
    for(i=0;i<len;i++){
        std::cout<<Ciphertext[i]<<" ";
        if((i+1)%4==0)
            std::cout<<"\n";
    }
    std::cout<<"\n======signature======\n";
    for(i=0;i<len;i++){
        std::cout<<ciphertext[i]<<" ";
        if((i+1)%4==0)
            std::cout<<"\n";
    }
}
void rsa::RSA_Vertify()//验证
{
    int len=32;//密文字符数组长度
    int i = 0;
    std::cout<<"========Signature====\n";
    for(i=0;i<len;i++){
        std::cout<<Ciphertext[i]<<" ";
        if((i+1)%4==0)
            std::cout<<"\n";
    }
    std::cout<<"\n";
    std::cout<<"=============";
    for(i = 0; i < len; i++){
        Plaintext[i] = Modular_Exonentiation(Ciphertext[i], e, n);//公钥验证
        plaintext[i]=(char)(Plaintext[i]);
    }
    std::cout<<"======明文======\n";
    for(i=0;i<len;i++){
        std::cout<<plaintext[i]<<" ";
        if(i%4==0&&i!=0)std::cout<<"\n";
    }
}
